__type__ = "rss"
__instance__ = "PyBtRss"

import logging
import urlparse
import urllib
import urllib2
import xml.sax
import re

try:
    import feedparser
except ImportError:
    print "Please install Feedparser from http://www.feedparser.org/ or from your distro repository"
    import sys
    sys.exit(1)

class PyBtRss:

    def passwordize(self, url, user, password):
        """Add username and password to url"""

        parts = list(urlparse.urlsplit(url))
        parts[1] = user+":"+password+"@"+parts[1]
        url = urlparse.urlunsplit(parts)
        return url        

    # TODO: convert returns to exception raises
    def run(self, feed, patterns, config, session):

        # use basic auth when needed
        if config.has_key('username') and config.has_key('password'):
            url = self.passwordize(url, config['username'], config['password'])

        logging.debug("Checking feed %s (%s)", feed, config['url'])

        # initialize per-feed configuration in session
        session.setdefault(feed, {})
        
        # check etags and last modified -headers
        etag = session[feed].get('etag', None)
        if etag:
            logging.debug("Sending etag %s for feed %s" % (etag, feed))
        modified = session[feed].get('modified', None)
        if modified:
            logging.debug("Sending last-modified %s for feed %s" % (etag, feed))

        # get the feed & parse
        try:
            rss = feedparser.parse(config['url'], etag=etag, modified=modified)
        except IOError:
            logging.error("IOError when loading feed %s", feed)
            return

        try:
            # status checks
            if rss.status == 304:
                logging.debug("Feed %s hasn't changed, skipping" % feed)
                return
            elif rss.status == 401:
                logging.warning("Authentication needed for feed %s: %s", feed, rss.headers['www-authenticate'])
                return
            elif rss.status == 404:
                logging.error("Feed %s not found", feed)
                return
            elif rss.status == 500:
                logging.error("Internal server exception on feed %s", feed)
                return
        except urllib2.URLError:
            logging.error("URLError on feed %s", feed)
            return
        except AttributeError, e:
            ex = rss['bozo_exception']
            if ex == feedparser.NonXMLContentType:
                logging.error("feedparser.NonXMLContentType")
                return
            elif ex == xml.sax._exceptions.SAXParseException:
                logging.error("xml.sax._exceptions.SAXParseException")
                return
            elif ex == urllib2.URLError:
                logging.error("urllib2.URLError")
                return
            else:
                logging.error("Unhandled bozo_exception. Type: %s.%s (source: %s)" % (ex.__class__.__module__, ex.__class__.__name__ , feed))
                return

        if rss['bozo']:
            logging.error(rss)
            logging.error("Bozo feed exception on %s. Is the URL correct?" % feed)
            return

        # update etag, use last modified if no etag exists
        if rss.has_key('etag') and type(rss['etag']) != feedparser.types.NoneType:
            session[feed]['etag'] = rss.etag.replace("'", "").replace('"', "")
            logging.debug("etag "+session[feed]['etag']+" saved for feed %s", feed)
        elif rss.headers.has_key('last-modified'):
            config['modified'] = rss.modified
            logging.debug("last modified saved for feed %s", feed)

        # process feed and find matching torrents
        matches = []
        for entry in rss.entries:
            # fix for crap feeds with no ID
            if not entry.has_key('id'):
                entry['id'] = entry.link
            # match title to given patterns            
            for pattern in patterns:
                regexp = str(pattern['pattern'])
                if re.search(regexp, entry.title, re.IGNORECASE|re.UNICODE):
                    logging.debug("%s matched pattern %s on %s" % (entry.title, regexp, feed))

                    # Fixes for "interesting" feed structures
                    if entry.link.startswith("http://www.mininova.org/tor/"):
                        entry.link = entry.link.replace('tor', 'get')
                    elif entry.link.startswith("http://www.torrentspy.com/torrent/"):
                        m = re.match("http://www.torrentspy.com/torrent/([\d]+)/", entry.link)
                        torrent_id = m.group(1)
                        entry.link = "http://www.torrentspy.com/download.asp?id=%s" % torrent_id

                    # Use basic auth when needed
                    if config.has_key('username') and config.has_key('password'):
                        logging.debug("Using basic auth for retrieval")
                        entry.link = self.passwordize(entry.link, config['username'], config['password'])

                    # add torrent link and title to matching pattern
                    match = pattern.copy()
                    match['torrent'] = entry.link
                    match['title'] = entry.title
                    matches.append(match)

        return matches
